package com.ding.easycontroller.helper;

import org.springframework.util.StreamUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class EcBufferResponse extends HttpServletResponseWrapper {

    private List<Closeable> closeables = new ArrayList<>();

    public EcBufferResponse(HttpServletResponse request) throws IOException {
        super(request);
    }

    @Override
    protected void finalize() throws Throwable {

        try {
            for (Closeable closeable : closeables) {
                closeable.close();
            }
        } catch (Exception e) {

        }

    }

    private ReadAbleOutputStream readAbleOutputStream;

    public BufferedInputStream getInputStream() {
        try {

            if (readAbleOutputStream == null) {
                readAbleOutputStream = new ReadAbleOutputStream(super.getOutputStream());
            }

            BufferedInputStream bufferedInputStream;

            if (readAbleOutputStream.byteArrayOutputStream != null) {
                bufferedInputStream = new BufferedInputStream(new ByteArrayInputStream(readAbleOutputStream.byteArrayOutputStream.toByteArray()));
            } else {
                bufferedInputStream = new BufferedInputStream(new FileInputStream(readAbleOutputStream.file));
            }

            closeables.add(bufferedInputStream);
            return bufferedInputStream;
        } catch (FileNotFoundException e) {
            return null;
        } catch (IOException e) {
            return null;
        }
    }

    public BufferedReader getReader() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(getInputStream()));

            closeables.add(reader);

            return reader;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        ServletOutputStream outputStream = getOutputStream();
        PrintWriter printWriter = new PrintWriter(outputStream){
            @Override
            public void write(String s, int off, int len) {
                super.write(s, off, len);
                flush();
            }

            @Override
            public void write(char[] buf) {
                super.write(buf);
                flush();
            }

            @Override
            public void write(String s) {
                super.write(s);
                flush();
            }

            @Override
            public void write(int c) {
                super.write(c);
                flush();
            }

            @Override
            public void write(char[] buf, int off, int len) {
                super.write(buf, off, len);
                flush();
            }
        };
        closeables.add(printWriter);
        return printWriter;
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {

        if (readAbleOutputStream == null) {
            readAbleOutputStream = new ReadAbleOutputStream(super.getOutputStream());
        }

        return readAbleOutputStream;
    }

    private static class ReadAbleOutputStream extends ServletOutputStream {

        //最大内存
        private static int max = 1024 * 1024 * 5;

        private OutputStream su;

        public ReadAbleOutputStream(OutputStream su) {
            this.su = su;
        }

        @Override
        public void flush() throws IOException {
            su.flush();
        }

        File file;

        private BufferedOutputStream outputStream;

        private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        @Override
        protected void finalize() throws Throwable {
            if (file != null) {
                file.delete();
            }
            byteArrayOutputStream.close();
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setWriteListener(WriteListener writeListener) {
        }

        @Override
        public void write(int b) throws IOException {//在持续的写入过程中,判断是否超出最大长度,

            su.write(b);

            if (byteArrayOutputStream == null) {
                writeToFile(b);
                return;
            }

            if (byteArrayOutputStream.size() > max) {
                byteArrayOutputStream = null;
                writeToFile(byteArrayOutputStream.toByteArray());
                return;
            }

            byteArrayOutputStream.write(b);
        }

        private void writeToFile(int b) {
            try {
                outputStream.write(b);
            } catch (IOException e) {
            }
        }

        private void writeToFile(byte[] b) {
            try {
                file = File.createTempFile("ec-response", ".tmp");
                outputStream = new BufferedOutputStream(new FileOutputStream(file));
                outputStream.write(b);
            } catch (IOException e) {
            }

        }

    }


    public String getStringBody() {

        byte[] byteArrayBody = getByteArrayBody();

        if (byteArrayBody == null) {
            return null;
        }

        return new String(byteArrayBody);
    }

    public byte[] getByteArrayBody() {
        BufferedInputStream inputStream = getInputStream();

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        try {
            StreamUtils.copy(inputStream, byteArrayOutputStream);
            return byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            return null;
        }
    }

}
